﻿using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace TranslatorService
{
	/// <summary>
	/// Capabilities available from the implemented translation service.
	/// </summary>
	[Flags]
	public enum TranslatorServiceCapabilities
	{
		/// <summary>Supports plain text input.</summary>
		PlainText = 0x001,
		/// <summary>Supports HTML input.</summary>
		HtmlText = 0x002,

		/// <summary>Translates single words.</summary>
		TranslatesWords = 0x0010,
		/// <summary>Translates phrases.</summary>
		TranslatesPhrases = 0x0020,
		/// <summary>Provides a method to define a word.</summary>
		DefinesWords = 0x0040,
		/// <summary>Able to detect the source or input language.</summary>
		DetectsLanguage = 0x0080,
		/// <summary>Provides a method allowing for user submissions.</summary>
		UserSubmissions = 0x0100,
		/// <summary>Provides a method to retrieve the pronunciation of translated text.</summary>
		ProvidesAudio = 0x0200,
		/// <summary>The service requires authentication.</summary>
		RequiresAuthentication = 0x0400
	}

	/// <summary>
	/// The format of the input text to the <see cref="ITranslatorService.TranslateAsync"/> method.
	/// </summary>
	public enum InputFormat
	{
		/// <summary>Input is plain text.</summary>
		Text,
		/// <summary>Input is in HTML.</summary>
		Html
	}

	/// <summary>
	/// Common interface for all translation services.
	/// </summary>
	public interface ITranslatorService
	{
		/// <summary>
		/// Gets the service capabilities.
		/// </summary>
		/// <value>
		/// The service capabilities.
		/// </value>
		TranslatorServiceCapabilities ServiceCapabilities { get; }

		/// <summary>
		/// Gets the name of the service.
		/// </summary>
		/// <value>
		/// The name of the service.
		/// </value>
		string ServiceName { get; }

		/// <summary>
		/// Gets the Url for the service.
		/// </summary>
		/// <value>
		/// The Url for the service.
		/// </value>
		Uri ServiceURI { get; }

		/// <summary>
		/// Gets a list of parameters that must be supplied to the <see cref="AuthenticateAsync"/> method.
		/// </summary>
		/// <value>
		/// The authentication parameters.
		/// </value>
		string[] AuthenticationParameterDetail { get; }

		/// <summary>
		/// Asynchronously authenticates to the service. If <see cref="ServiceCapabilities"/> returns <see cref="TranslatorServiceCapabilities.RequiresAuthentication"/> then this method must be called before calling any other methods of the instance.
		/// </summary>
		/// <remarks>
		/// When implemented, the instance should hold the authentication token for use in all the other method calls.
		/// </remarks>
		/// <param name="options">The strings needed for authentication. The <see cref="AuthenticationParameterDetail"/> property defines the order and required parameters.</param>
		/// <returns>A <code>boolean</code> value indicating authentication success or failure.</returns>
		Task<bool> AuthenticateAsync(params string[] options);

		/// <summary>
		/// Asynchronously gets the languages that are supported by the service. 
		/// </summary>
		/// <param name="local">The local language. This is used for returning the language names in a specific locale if possible.</param>
		/// <returns>A <see cref="Task"/> holding a <c>Dictionary</c> of <c>string</c> values. The <c>Key</c> for the dictionary is the language code and <c>Value</c> is the language name translated in the locale specified by the <paramref name="local"/> parameter.</returns>
		Task<Dictionary<string, string>> GetSupportedLanguagesAsync(string local = "en");

		/// <summary>
		/// Asynchronously translates the <paramref name="value"/> from the language defined by <paramref name="sourceLang"/> into the language defined by <paramref name="destLang"/>.
		/// </summary>
		/// <param name="sourceLang">The source language. This should be a <c>Key</c> returned by the <see cref="GetSupportedLanguagesAsync"/> method. If <see cref="ServiceCapabilities"/> returns <see cref="TranslatorServiceCapabilities.DetectsLanguage"/> then this parameter can be set to <c>null</c>.</param>
		/// <param name="destLang">The destination language. This should be a <c>Key</c> returned by the <see cref="GetSupportedLanguagesAsync"/> method.</param>
		/// <param name="value">The word or phrase to be translated. If <see cref="ServiceCapabilities"/> returns <see cref="TranslatorServiceCapabilities.TranslatesWords"/> then only single words are accepted. If <see cref="ServiceCapabilities"/> returns <see cref="TranslatorServiceCapabilities.TranslatesPhrases"/> then phrases are accepted.</param>
		/// <param name="format">The format of the result. This value can either be <c>InputFormate.Text</c> or <c>InputFormate.Html</c>. <see cref="ServiceCapabilities"/> defines which result type is supported via the <see cref="TranslatorServiceCapabilities.PlainText"/> or <see cref="TranslatorServiceCapabilities.HtmlText"/> values.</param>
		/// <returns>On success, the translated word or phrase.</returns>
		Task<string> TranslateAsync(string sourceLang, string destLang, string value, InputFormat format = InputFormat.Text);

		/// <summary>
		/// Asynchronously detects the language of the provided value.
		/// </summary>
		/// <param name="value">The text of which to determine the language.</param>
		/// <returns>A langauage code.</returns>
		Task<string> DetectLanguageAsync(string value);

		/// <summary>
		/// Asynchronously calls a service method.
		/// </summary>
		/// <typeparam name="T">The expected <see cref="Type"/> of the result.</typeparam>
		/// <param name="methodName">Name of the service method.</param>
		/// <param name="parameters">The parameters supplied to the method. These are typically name/value pairs supplied as sequential items. For example, if the method requires a name/value pair to specify the target language, one would supply <code>"target", "en"</code> as two sequential parameters.</param>
		/// <returns>The method result cast to the type defined by <typeparamref name="T"/>.</returns>
		Task<T> CallMethodAsync<T>(string methodName, params string[] parameters) where T : class;
	}
}
